package com.itheima.filter;

import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    //要过滤数据库SQL的关键字
    private final static String key = "and|exec|insert|select|delete|update|count|chr|mid|master|truncate|char|declare|or";
    private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
    //SQL过滤到要加的标记文字
    private static String replacedString = "INVALID";
    //是否要过滤HTML符号
    public static Boolean HTML_TYPE = true;
    //是否要过滤SQL关键字
    public static Boolean SQL_TYPE = true;

    static {
        String keyStr[] = key.split("\\|");
        for (String str : keyStr) {
            notAllowedKeyWords.add(str);
        }
    }

    private String currentUrl;

    public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
        currentUrl = servletRequest.getRequestURI();
    }


    /**
     * 覆盖getParameter方法，将参数名和参数值都做xss过滤。
     * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取
     * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
     */
    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = cleanXSS(values[i]);
        }
        return encodedValues;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> values = super.getParameterMap();
        if (values == null) {
            return null;
        }
        Map<String, String[]> result = new HashMap<>();
        for (String key : values.keySet()) {
            String encodedKey = cleanXSS(key);
            int count = values.get(key).length;
            String[] encodedValues = new String[count];
            for (int i = 0; i < count; i++) {
                encodedValues[i] = cleanXSS(values.get(key)[i]);
            }
            result.put(encodedKey, encodedValues);
        }
        return result;
    }

    /**
     * 覆盖getHeader方法，将参数名和参数值都做xss过滤。
     * 如果需要获得原始的值，则通过super.getHeaders(name)来获取
     * getHeaderNames 也可能需要覆盖
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    /**
     * 过滤HTML,CSS,JS中的一些特殊字符，比如 <> () '
     *
     * @param valueP
     * @return
     */
    private String cleanXSS(String valueP) {
        String value = valueP;
        //判断是否过滤HTML字符，是则过滤
        if(HTML_TYPE){
            value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
            value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
            value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
            value = value.replaceAll("'", "&#39;");
            value = value.replaceAll("eval\\((.*)\\)", "");
            value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
            value = value.replaceAll("alert", "");
        }
        //判断是否过滤SQL关键字，是则过滤
        if(SQL_TYPE){
            value = cleanSqlKeyWords(value);
        }
        return value;
    }

    /**
     * 过滤SQL关键字
     *
     * @param value
     * @return
     */
    private String cleanSqlKeyWords(String value) {
        String paramValue = value;
        if (value.indexOf("q=0.01") == -1) {
            for (String keyword : notAllowedKeyWords) {
                if (paramValue.length() > keyword.length() + 4 && (paramValue.contains(" " + keyword) || paramValue.contains(keyword + " ") || paramValue.contains(" " + keyword + " "))) {
                    paramValue = StringUtils.replace(paramValue, keyword, replacedString);
                }
            }
        }
        return paramValue;
    }

}

